package jgrit.gui.export;

import java.awt.Color;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

import javax.swing.AbstractAction;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.text.AttributeSet;
import javax.swing.text.DefaultStyledDocument;
import javax.swing.text.Document;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;


import com.jgoodies.forms.factories.ButtonBarFactory;
import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;

/**
 * Show a window with the Grit status messages
 * 
 * @author Sam Hartsfield, Derek Olejnik, Taylor Perkins
 *
 */
public class ExportOutputWindow {
	
	private String messages;
	
	private int warningCount;
	private int errorCount;
	
	private JLabel summaryLabel;
	
	private JFrame frame;
	private JTextPane msgPane;
	
	private enum TextPrefix {
		WARNING,
		ERROR,
		STATUS,
		NONE
	}
	
	public ExportOutputWindow(String messages) {
		this.messages = messages;
		this.warningCount = 0;
		this.errorCount = 0;
		initGUI();
	}
	
	public void setMsgString(String messages) {
		this.messages = messages;
		addFormattedMessages();
		summaryLabel.setText(getSummaryText());
	}
	
	public String getMsgString() {
		return this.messages;
	}
	
	/**
	 * Set the location of the window relative to another component.
	 * 
	 * @see Window#setLocationRelativeTo(Component)
	 * @param c the component in relation to which the window's location
     *           is determined
	 */
	public void setLocationRelativeTo(Component c) {
		frame.setLocationRelativeTo(c);
	}
	
	private void initGUI() {
		frame = new JFrame("Grit Output");
		frame.setLocationByPlatform(true);
		frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
		
		CellConstraints cc = new CellConstraints();
		
		final JButton okButton = new JButton(new AbstractAction("OK") {
			private static final long serialVersionUID = 1L;

			//This job has been delegated down from the MainGUI
			public void actionPerformed(ActionEvent e) {
				frame.dispose();
			}
		});
		
		/*
		 * "default" (as opposed to "pref") tries to use the preferred size,
		 * but also will allow the column to shrink to the minimum size.
		 * 
		 * Set a max size for the column and row to try to keep things from
		 * going off the screen.
		 */
		FormLayout layout = new FormLayout("$dmargin, [200dlu, default, 300dlu]:grow, $dmargin",
				"$dmargin, [100dlu, default, 200dlu]:grow, $rgap, p, $dmargin");
		JPanel panel = new JPanel(layout);
		
		msgPane = new JTextPane();
		msgPane.setEditable(false);

		/*
		 * Add a key listener to close the frame when the user presses enter
		 * (actually, click on the OK button, so that it looks like it's
		 * supposed to, i.e. replicates the behavior of pressing enter in the
		 * root pane when the OK button is set as the default button).
		 */
		msgPane.addKeyListener(new KeyAdapter() {
			@Override
			public void keyReleased(KeyEvent e) {
				if (e.getKeyCode() == KeyEvent.VK_ENTER) {
					okButton.doClick();
				}
			}
		});

		JScrollPane msgScroll = new JScrollPane(msgPane);
		panel.add(msgScroll, cc.xy(2, 2, "fill, fill"));
		addFormattedMessages();
		
		summaryLabel = new JLabel(getSummaryText());		
		panel.add(summaryLabel, cc.xy(2, 4));
		
		panel.add(ButtonBarFactory.buildOKBar(okButton), cc.xy(2, 4));
		frame.getRootPane().setDefaultButton(okButton);
		
		frame.add(panel);
		frame.pack();
		
		frame.setIconImage(new ImageIcon(getClass()
			.getResource("/jgrit/gui/icons/jgritIcon.png")).getImage());
	}
	
	/**
	 * @return A summary of the export status (failed, succeeded, N errors)
	 */
	private String getSummaryText() {
		if (errorCount > 0) {
			return "Export failed. " + errorCount + " error(s).";
		} else if (warningCount > 0) {
			return "Exported successfully with " + warningCount + " warning(s).";
		} else {
			return "Exported successfully.";
		}
	}
	
	/**
	 * Formats the messages and puts them in the text pane
	 */
	private void addFormattedMessages() {
		Document outputDoc = new DefaultStyledDocument();
		AttributeSet defaultText = msgPane.getStyle("default");
		
		SimpleAttributeSet statusText = new SimpleAttributeSet();
		StyleConstants.setForeground(statusText, Color.GREEN.darker());
		StyleConstants.setBold(statusText, true);
		
		SimpleAttributeSet warningText = new SimpleAttributeSet();
		StyleConstants.setForeground(warningText, Color.ORANGE.darker());
		StyleConstants.setBold(warningText, true);
		
		SimpleAttributeSet errorText = new SimpleAttributeSet();
		StyleConstants.setForeground(errorText, Color.RED);
		StyleConstants.setBold(errorText, true);
		
		while (messages.length() > 0) {
			int firstWarningIndex = messages.indexOf("WARNING");
			int firstErrorIndex = messages.indexOf("ERROR");
			int firstStatusIndex = messages.indexOf("STATUS");
			TextPrefix minPrefix = TextPrefix.NONE;
			int minIndex = messages.length();
			
			if (firstWarningIndex >= 0 && firstWarningIndex < minIndex) {
				minIndex = firstWarningIndex;
				minPrefix = TextPrefix.WARNING;
			}
			if (firstErrorIndex >= 0 && firstErrorIndex < minIndex) {
				minIndex = firstErrorIndex;
				minPrefix = TextPrefix.ERROR;
			}
			if (firstStatusIndex >= 0 && firstStatusIndex < minIndex) {
				minIndex = firstStatusIndex;
				minPrefix = TextPrefix.STATUS;
			}
			
			switch(minPrefix) {
				case STATUS:
					try {
						outputDoc.insertString(outputDoc.getLength(), 
								messages.substring(0, firstStatusIndex), 
								defaultText);
						outputDoc.insertString(outputDoc.getLength(), 
								messages.substring(firstStatusIndex, 
										firstStatusIndex + "STATUS".length()), 
								statusText);
						messages = messages.substring(firstStatusIndex + 
								"STATUS".length());
					} catch (Exception e) {
						ExportDialog.displayError("Error on Grit Msg", 
								"Error inserting message in GritStatus", e);
					}		
					break;
				case WARNING:
					try {
						outputDoc.insertString(outputDoc.getLength(), 
								messages.substring(0, firstWarningIndex), 
								defaultText);
						outputDoc.insertString(outputDoc.getLength(), 
								messages.substring(firstWarningIndex, 
										firstWarningIndex + "WARNING".length()), 
								warningText);
						messages = messages.substring(firstWarningIndex + 
								"WARNING".length());
						warningCount++;
						
					} catch (Exception e) {
						ExportDialog.displayError("Error on Grit Msg", 
								"Error inserting message in GritStatus", e);
					}		
					break;
				case ERROR:
					try {
						outputDoc.insertString(outputDoc.getLength(), 
								messages.substring(0, firstErrorIndex), 
								defaultText);
						outputDoc.insertString(outputDoc.getLength(), 
								messages.substring(firstErrorIndex, 
										firstErrorIndex + "ERROR".length()), 
								errorText);
						messages = messages.substring(firstErrorIndex + 
								"ERROR".length());
						errorCount++;
					} catch (Exception e) {
						ExportDialog.displayError("Error on Grit Msg", 
								"Error inserting message in GritStatus", e);
					}
					break;
				case NONE:
				default:
					try {
						outputDoc.insertString(outputDoc.getLength(), messages, 
								defaultText);
					} catch (Exception e) {
						ExportDialog.displayError("Error on Grit Msg", 
								"Error inserting message in GritStatus", e);
					}
					messages = ""; //We are done now
					break;
			}
		}
		
		msgPane.setDocument(outputDoc);
	}
	
	public void setVisible(boolean b) {
		frame.setVisible(b);
	}
	
	/**
	 * @param args
	 */
	public static void main(String[] args) {
//		GritStatus s = new GritStatus("STATUS: ---grit v0.8.1 ---\nSTATUS: Individual runs.\nSTATUS: Input file E:\\Sam\\sprites\\Mario\\RacoonMarioKick.png\nSTATUS: Output file: 'E:\\Sam\\sprites\\Mario\\RacoonMarioKick.c'.\nSTATUS: Started run at: 2008-10-17, 17:45:52\nSTATUS: Validatating gr.\nSTATUS: Validation succeeded.\nSTATUS: Preparing data.\nSTATUS: Work-DIB creation.\nWARNING:   converting from 8 bpp to 16 bpp.\nSTATUS: converting to: 16bpp, BGR.\nSTATUS: Work-DIB creation complete: 22x28@16.\nSTATUS: Tile preparation.\nSTATUS: Tile preparation complete.\nSTATUS: Graphics preparation.\nSTATUS: Graphics preparation complete.\nSTATUS: Data preparation complete.\nSTATUS: Export to C: RacoonMarioKick into E:\\Sam\\sprites\\Mario\\RacoonMarioKick.c .\nSTATUS: Run completed :).\nSTATUS: Done!");
		ExportOutputWindow s = new ExportOutputWindow("STATUS: ---grit v0.8.1 ---\nSTATUS: Individual runs.\nSTATUS: Input file E:\\Sam\\sprites\\Mario\\RacoonMarioKick.png\nSTATUS: Output file: 'E:\\Sam\\sprites\\Mario\\RacoonMarioKick.c'.\nSTATUS: Started run at: 2008-10-17, 17:45:52\nSTATUS: Validatating gr.\nSTATUS: Validation succeeded.\nSTATUS: Preparing data.\nSTATUS: Work-DIB creation.\nWARNING:   converting from 8 bpp to 16 bpp.\nSTATUS: converting to: 16bpp, BGR.\nSTATUS: Work-DIB creation complete: 22x28@16.\nSTATUS: Tile preparation.\nSTATUS: Tile preparation complete.\nSTATUS: Graphics preparation.\nSTATUS: Graphics preparation complete.\nSTATUS: Data preparation complete.\nSTATUS: Export to C: RacoonMarioKick into E:\\Sam\\sprites\\Mario\\RacoonMarioKick.c .\nSTATUS: Run completed :).\nSTATUS: Done!\nSTATUS: ---grit v0.8.1 ---\nSTATUS: Individual runs.\nSTATUS: Input file E:\\Sam\\sprites\\Mario\\RacoonMarioKick.png\nSTATUS: Output file: 'E:\\Sam\\sprites\\Mario\\RacoonMarioKick.c'.\nSTATUS: Started run at: 2008-10-17, 17:45:52\nSTATUS: Validatating gr.\nSTATUS: Validation succeeded.\nSTATUS: Preparing data.\nSTATUS: Work-DIB creation.\nWARNING:   converting from 8 bpp to 16 bpp.\nSTATUS: converting to: 16bpp, BGR.\nSTATUS: Work-DIB creation complete: 22x28@16.\nSTATUS: Tile preparation.\nSTATUS: Tile preparation complete.\nSTATUS: Graphics preparation.\nSTATUS: Graphics preparation complete.\nSTATUS: Data preparation complete.\nSTATUS: Export to C: RacoonMarioKick into E:\\Sam\\sprites\\Mario\\RacoonMarioKick.c .\nSTATUS: Run completed :).\nSTATUS: Done!\nSTATUS: ---grit v0.8.1 ---\nSTATUS: Individual runs.\nSTATUS: Input file E:\\Sam\\sprites\\Mario\\RacoonMarioKick.png\nSTATUS: Output file: 'E:\\Sam\\sprites\\Mario\\RacoonMarioKick.c'.\nSTATUS: Started run at: 2008-10-17, 17:45:52\nSTATUS: Validatating gr.\nSTATUS: Validation succeeded.\nSTATUS: Preparing data.\nSTATUS: Work-DIB creation.\nWARNING:   converting from 8 bpp to 16 bpp.\nSTATUS: converting to: 16bpp, BGR.\nSTATUS: Work-DIB creation complete: 22x28@16.\nSTATUS: Tile preparation.\nSTATUS: Tile preparation complete.\nSTATUS: Graphics preparation.\nSTATUS: Graphics preparation complete.\nSTATUS: Data preparation complete.\nSTATUS: Export to C: RacoonMarioKick into E:\\Sam\\sprites\\Mario\\RacoonMarioKick.c .\nSTATUS: Run completed :).\nSTATUS: Done!");
		s.setVisible(true);
	}

}
